/**
 * @param {string} str1
 * @remark 变量提升1
 */
function frist(str1) {
    var f = function () {
      return 2
    }
    console.log('>>>print', 3, f())

    function f() {
      return 4
    }
    console.log('>>>print', 5, f())
   
    return f()
  }
  
// console.log(frist())
/*
>>>print 3 2
>>>print 5 2
2
*/

/**
 * @param {string} str2
 * @remark 变量提升2
 * @remark >>>print 2后面不接3，是因为第一个函数没有传输口（第二个函数同理）；>>>print 3 3（第二个3是变量提升的结果），后接>>>print 2和3是变量提升，且返回最终函数的全部。
 *@remark 函数的变量提升是一个函数直接干掉另一个。
 */
function frist2(str2) {
    console.log('>>>print', 1)
    
    var f = function () {
      console.log('>>>print', 2) 
      return 3
    }
  
    console.log('>>>print', 3, f())
  
    function f() {
      console.log('>>>>>print', 4)
      return 5
    }
  
    console.log('>>>print', 5, f())
    return f()
}
  
// console.log('>>>print', 6)
// console.log(frist2())
// console.log('>>>print', 7)
/*
>>>print 6
>>>print 1
>>>print 2
>>>print 3 3
>>>print 2
>>>print 5 3
>>>print 2
3
>>>print 7
*/

/**
 * @param {string} str3
 * @remark 闭包
 */
function frist3(str3) {
    const closure = () => {
        var a = 10;
        a = 12 // 1. 作用域内部是可以修改变量的
        return function fn(c) {
            a = c ? c : a
            return a
        }
    }
    a = 33 // 2. 现在我在外部去修改a这个变量，我是无法修改closure内部的a，原因是我访问不到closure内部的a
    console.log('>>>>a33', a) // 3.打印33 这是一个新的变量，不是closure内部的a

    const getValue = closure() // 4. 看看我们不改变closure内部的a的时候，拿到closure内部的a的值
    const unchangedValue = getValue() // 5. 打印12，并且我们能够在closure作用于外，拿到a的值了
    console.log('>>>>unchangedValue', unchangedValue) // 6.改变之前的值

    const changedValue = getValue(22)// 7.闭包不仅可以在作用域外，访问到a，并且可以在作用域外修改a
    console.log('>>>>changedValue', changedValue) // 8. 打印22
}
// console.log(frist3())
/*
>>>>a33 33
>>>>unchangedValue 12
>>>>changedValue 22
undefined//最外层函数没返回值
*/

/**
 * @param {string} str4 
 * @remark return 与console.log ,函数只返回return后面的东西，而console.log（用于调试）是打印在控制台，与函数无关。
 */
function first4 (str4){
  function f() {
      try {
        console.log(0);
        throw 'bug';
      } catch(e) {
        console.log(1);
        return true; // 这句原本会延迟到 finally 代码块结束再执行
        console.log(2); // 不会运行
      } finally {
        console.log(3);
        return false; // 这句会覆盖掉前面那句 return
        console.log(4); // 不会运行
      }
      console.log(5); // 不会运行
  }
  var result = f();
  console.log(6)
  return result
}
// console.log(first4())// 0 1 3 6 false



//不知道放哪
// function getSunmary(a, b) {
//   return a + b
// }
// function getSubstract(a,b){
//   return a-b;
// }
// const compareTwoNumber = (a,b)=>{
//   const sum = getSunmary(a,b);
//   const sub = getSubstract(a,b);
//   return {
//       sum,
//       sub
//   }
// }
// const res = compareTwoNumber(1,2)
// // console.log(res)

/**
 * @param {string} str5
 * @remark valueOf()和toString()
 */
function first5(str5) {
  let obj = {}
  console.log(obj.valueOf())
  console.log(obj.toString())
}

// console.log(first5())
/*
 {}
 [object Object]
 undefined
*/


/**
 * @param {string} str6
 * @result Object.getOwnPropertyDescriptor()、Object.getOwnPropertyNames、Object.defineProperty()
 */
function first6(str6) {
  function f1(){
    var obj = { p: 'a' };
    return Object.getOwnPropertyDescriptor(obj, 'p')
  }

  function f2(){
    var obj = { p: 'a' };
    return Object.getOwnPropertyNames(obj)
  } 

  function f3(){
    var obj = { p: 'a' };
    return Object.defineProperty(obj, 'p',{value:'b'})
  }
  
  function f4(){
    var obj = { p: 'a' };
    Object.defineProperty(obj, 'p',{value:'b'})
    return obj.p
  }

  function f5(){
    var o1 = Object.defineProperty({}, 'p', {
      value: 1,
      writable: true,
      configurable: true
    });
      
    return Object.defineProperty(o1, 'p', {value: 2})
  }

  return {
    return1:f1(),
    return2:f2(),
    return3:f3(),
    return4:f4(),
    return5:f5()
  }
}
// console.log(first6())
/*
{
  return1: { value: 'a', writable: true, enumerable: true, configurable: true }
  return2: [ 'p' ] 
  return3: { p: 'b' }
  return4: 'b' 
  return5: {}
}
*/

// function f() {
//   var o1 = Object.defineProperty({}, 'p', {
//     value: 1,
//     writable: true,
//     configurable: false
//   });
  
//   return Object.defineProperty(o1, 'p', {value: 2})
//     }   
//   console.log(f())

var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 1, 1, 2)
// console.log(a) // ['a', 'b', 'c', 'd', 1, 2]

function first80(str80) {
  var a = ['a', 'b', 'c', 'd', 'e', 'f'];
  function f1(){
    a.splice(4, 1, 1, 2)
    return a
}
  function f2(){
    a.splice(-4, 2) 
    return a
  }
  return{
    s1: f1(),
    s2:f2()
  }
}
// console.log(first80())



function first6(str6) {
  function f1(){
    var obj = { p: 'a' };
    return Object.getOwnPropertyDescriptor(obj, 'p')
  }
  function f2(){
    var obj = { p: 'a' };
    return Object.getOwnPropertyNames(obj)
  } 
  function f3(){
    var obj = { p: 'a' };
    return Object.defineProperty(obj, 'p',{value:'b'})
  }
  function f4(){
    var obj = { p: 'a' };
    Object.defineProperty(obj, 'p',{value:'b'})
    return obj.p
  }
  function f5(){
    var o1 = Object.defineProperty({}, 'p', {
      value: 1,
      writable: true,
      configurable: true
    });
    return Object.defineProperty(o1, 'p', {value: 2})
  }
  return {
    return1:f1(),
    return2:f2(),
    return3:f3(),
    return4:f4(),
    return5:f5()
  }
}
console.log(first6())
/*
{
  return1: { value: 'a', writable: true, enumerable: true, configurable: true }
  return2: [ 'p' ] 
  return3: { p: 'b' }
  return4: 'b' 
  return5: {}
}
*/